package example;

import java.sql.Connection;
import java.sql.Date;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;



/**
 * Created by IntelliJ IDEA.
 * User: stermi
 * Date: 29-nov-2009
 * Time: 11.13.21
 * To change this template use File | Settings | File Templates.
 */
public class Film {

    public static final String tabName = "film";

    public static final String idField = "id";
    public static final String titoloField = "titolo";
    public static final String categoriaIdField = "categoria_id";
    public static final String descrizioneField = "descrizione";
    public static final String annoField = "anno";
    public static final String uscitaField = "uscita";
    public static final String votoField = "voto";
    public static final String durataField = "durata";
    public static final String copieTotaliField = "copietotali";
    public static final String copieRimasteField = "copierimaste";
    public static final String visibileField = "visibile";

    int id;
    int categoriaId;
    Categoria categoria;
    ArrayList<Regista> registi;
    ArrayList<Scrittore> scrittori;
    ArrayList<Attore> attori;

    //TODO quando possibile, aggiungere la locandina
    String titolo;
    String descrizione;
    int anno;
    Date uscita;
    double voto;
    int durata; // Minuti
    int copieTotali; //numero delle copie nello store
    int copieRimaste;
    boolean visibile;

    
    
    public Film() {
    	
    	this.id = -1;
    	this.categoria = null;
    	this.categoriaId = -1;
    	this.registi = new ArrayList<Regista>();
    	this.scrittori = new ArrayList<Scrittore>();
    	this.attori = new ArrayList<Attore>();
    	this.visibile = false;
    	
    }
    
    public String durataToString() {
        return ( this.durata / 60 ) + "h " + ( this.durata % 60 ) + "m";
    }
    
    public Result validate() {
    	Result result = new Result( true, null, "" );
    	
    	if ( titolo.trim().equals("") ) { 
    		result.result = false;
    		result.errorMessage += "Il titolo non puo' essere vuoto\n";
    	}
    	
    	if ( categoriaId < 0 ) { // TODO: ricerca su db se esiste la categoria? Dato sicuramente sicuro?
    		result.result = false;
    		result.errorMessage += "Categoria invalida\n";
    	}
    	
    	if ( anno < 1800 ) { 
    		result.result = false;
    		result.errorMessage += "Anno di uscita invalido\n";
    	}
    	
    	if ( voto < 0 || voto > 10 ) { 
    		result.result = false;
    		result.errorMessage += "Voto invalido, deve essere >=0 e <= 10\n";
    	}
    	
    	if ( durata < 0 ) {
    		result.result = false;
    		result.errorMessage += "Durata del film deve essere un numero positivo\n";
    	}
    	
    	if ( copieTotali < 0 || copieRimaste < 0 ) { 
    		result.result = false;
    		result.errorMessage += "Le copie totali e copie rimaste devono essere maggiori di zero\n";
    	}
    	
    	if ( copieTotali < copieRimaste ) { 
    		result.result = false;
    		result.errorMessage += "Le copie totali devono essere maggiori o uguali alle copie rimaste\n";
    	}
    	
    	return result;
    }
    
    
    public Result loadCategoria( Connection c ) {
    	// LOADA DAL DB L'AUTORE CON IL FILM
        this.categoria = new Categoria();
        return this.categoria.load(this.categoriaId, c);
    }
    
    private Result loadComponent( Connection c, String tableName, String tableCostrainName, String fieldName ) {
    	Result result;
    	
    	ArrayList<Persona> component = new ArrayList<Persona>();
    	PreparedStatement pstmt = null;
        ResultSet rs = null;
        String sqlQuery = "SELECT * FROM " + tableName + " WHERE "+ tableCostrainName + " = ?";
        try {
        	c.setAutoCommit(false);
        	pstmt = c.prepareStatement(sqlQuery);
        	pstmt.setInt(1, this.id  );
	        rs = pstmt.executeQuery();
	        // Ho >1 record quindi devo scorrerli tutti.
	        if ( rs != null )
	        	result = new Result( true, null, "Record caricati dalla tabella: " + tableName );
	        else
	        	result = new Result( false, null, "Errore di caricamento dei record dalla tabella " + tableName );
	        while ( rs.next() ) {
	        	Persona tempP = new Persona();
	        	tempP.load( rs.getInt(fieldName), c); //gestisci il return boolean
	        	component.add( tempP );
	        	
	        	
	        } /*else {
	        	//errore, non c'era il record sul db
	        	System.out.println("La categoria con id " + this.id + " non e' presente sul database.");
	        	component = null;
	        }*/
	        c.setAutoCommit(true);
	        
        } catch (SQLException e) {
        	System.out.println( "Errore generale: " +e.getMessage());
            result = new Result ( false, null, "Errore SQLException: " +e.getMessage() + "\nRecord non caricati dalla tabella " + tableName + " per il film " + this.id );
        } finally {
            try{
                if( rs != null )
                    rs.close();
                if( pstmt != null )
                    pstmt.close();
            } catch(Exception e){
                System.out.println( "Rilascio risorse non riuscito: "+e.getMessage());
                result = new Result ( false, null, "Rilascio risorse non riuscito: "+e.getMessage() + "\nRecord non caricati dalla tabella " + tableName + " per il film " + this.id );
            }
        }
        if ( result.result )
        	result.value = component;
    	return result;
    }
    
    private Result loadRegisti( Connection c ) {
    	// LOADA DAL DB L'AUTORE CON IL FILM
    	Result r;
    	r = loadComponent( c, Regista.tabName, Regista.filmIdField, Regista.personaIdField );
    	if ( r.result ) {
    		ArrayList<Persona> t = (ArrayList<Persona>)r.value;
	    	for ( Persona p: t )
	    		this.registi.add( new Regista( p, this.id ) );
    	} else {
    		if ( Test.DEBUG ) System.out.println( r.errorMessage );
    	}
    	return r;
    }
    
    private Result loadScrittori( Connection c ) {
    	// LOADA DAL DB L'AUTORE CON IL FILM
    	
    	Result r;
    	r = loadComponent( c, Scrittore.tabName, Scrittore.filmIdField, Scrittore.personaIdField );
    	if ( r.result ) {
    		ArrayList<Persona> t = (ArrayList<Persona>)r.value;
	    	for ( Persona p: t )
	    		this.scrittori.add( new Scrittore( p, this.id ) );
    	} else {
    		if ( Test.DEBUG ) System.out.println( r.errorMessage );
    	}
    	return r;
    }
    
    private Result loadAttori( Connection c ) {
    	// LOADA DAL DB L'AUTORE CON IL FILM
    	
    	Result r;
    	r = loadComponent( c, Attore.tabName, Attore.filmIdField, Attore.personaIdField );
    	if ( r.result ) {
    		ArrayList<Persona> t = (ArrayList<Persona>)r.value;
	    	for ( Persona p: t )
	    		this.attori.add( new Attore( p, this.id ) );
    	} else {
    		if ( Test.DEBUG ) System.out.println( r.errorMessage );
    	}
    	return r;
    	
    }
    
    public Result load( int id, Connection c )  {
        // load it from DB
    	Result result = null;
    	boolean noError = true;
    	PreparedStatement pstmt = null;
        ResultSet rs = null;
    	
    	String sqlQuery = "SELECT * FROM " + tabName + " WHERE "+ idField + " = ?";
    	
    	this.id = this.id > 0 ? this.id : id;
    	
    	try {
    		
    		c.setAutoCommit(false);
    		
			pstmt = c.prepareStatement(sqlQuery);
			pstmt.setInt(1, this.id  );
	        rs = pstmt.executeQuery();
	        
	        if ( rs.next() ) {
	        	this.set( rs );
	        	noError = this.loadCategoria(c).result;
	        	noError &= this.loadAttori(c).result;
	        	noError &= this.loadScrittori(c).result;
	        	noError &= this.loadRegisti(c).result;
	        	if ( noError )
	        		result = new Result(noError, this, "Film " + this.id + " caricato con successo");
	        	else
	        		result = new Result(noError, null, "Errore durante il caricamento del film con ID " + this.id);
	        	
	        } else {
	        	//errore, non c'era il record sul db
	        	System.out.println("Il film con id " + this.id + " non e' presente sul database.");
	        	result = new Result(false, null, "Il film con id " + this.id + " non e' presente sul database.");
	        }
	        
	        rs.close();
	        pstmt.close();
	        c.commit();
	        
	        
	        
		} catch (SQLException e) {
			System.out.println( "SQL Exception: " +e.getMessage());
            result = new Result(false, null,  "SQL Exception: " +e.getMessage() + " per film con ID " + this.id );
        } finally {
            try{
                if( rs != null )
                    rs.close();
                if( pstmt != null )
                    pstmt.close();
            } catch(Exception e){
                System.out.println(" Rilascio risorse non riuscito: "+e.getMessage());
            }
        }
		
		return result;
    	
    	
    }

    //Questo metodo viene solitamente usato per settare i parametri di un oggetto compilato da form
    private void set ( ResultSet rs ) throws SQLException {
    	this.id = rs.getInt( idField );
    	this.titolo = rs.getString( titoloField );
    	this.categoriaId = rs.getInt( categoriaIdField );
    	this.descrizione = rs.getString( descrizioneField );
    	this.anno = rs.getInt( annoField );
    	this.uscita = rs.getDate( uscitaField );
    	this.voto = rs.getDouble( votoField );
    	this.durata = rs.getInt( durataField );
    	this.copieTotali = rs.getInt( copieTotaliField );
    	this.copieRimaste = rs.getInt( copieRimasteField );
    	this.visibile = rs.getBoolean( visibileField );
    }
    
    public void set ( Film o ) {
    	this.id = o.id;
    	this.titolo = o.titolo;
    	this.categoriaId = o.categoriaId;
    	this.descrizione = o.descrizione;
    	this.anno = o.anno;
    	this.uscita = o.uscita;
    	this.voto = o.voto;
    	this.durata = o.durata;
    	this.copieTotali = o.copieTotali;
    	this.copieRimaste = o.copieRimaste;
    	this.visibile = o.visibile;
    	this.categoria = o.categoria;
    	this.registi = o.registi;
    	this.scrittori = o.scrittori;
    	this.attori = o.attori;
    }
    
    public Result save( Connection c ) {
    	return save(c, true);
    }
    
    public Result save( Connection c, boolean validate ) {
        
    	
    	Result result = null;
    	int rowAffected;
    	boolean insert;
    	
    	String query = "";
    	PreparedStatement pstmt = null;
    	ResultSet rs = null;
    	
    	if ( validate ) {
    		result = validate();
    		if ( !result.result )
    			return result;
    	}
    	
    	try {
    		
    		c.setAutoCommit(false);
    		
	    	if ( this.id < 1 ) { //non e' un nuovo record
	    		query = "INSERT INTO "+ tabName +" ( " + idField + ", " + categoriaIdField + ", " + titoloField + ", " + descrizioneField + ", " + annoField + ", " + uscitaField + ", " + votoField + ", " + durataField + ", " + copieTotaliField + ", " + copieRimasteField + ", " + visibileField +  "  ) VALUES (DEFAULT,?,?,?,?,?,?,?,?,?,?)";
	    		insert = true;
	    		pstmt = c.prepareStatement(query, Statement.RETURN_GENERATED_KEYS);
	    		
	    	} else {
	    		c.setTransactionIsolation(Connection.TRANSACTION_SERIALIZABLE);
	    		query = "UPDATE "+ tabName +" SET " + categoriaIdField + " = ?, " + titoloField + " = ?, " + descrizioneField + " = ?, " + annoField + " = ?, " + uscitaField + " = ?, " + votoField + " = ?, " + durataField + " = ?, " + copieTotaliField + " = ?, " + copieRimasteField +  " = ?, " + visibileField + " = ? WHERE " + idField + " = ?";
	    		insert = false;
	    		pstmt = c.prepareStatement(query);
	    		
	    	}
	    	
	    	pstmt.setInt(1, this.categoriaId );
	    	pstmt.setString(2, this.titolo  );
	    	pstmt.setString(3, this.descrizione  );
	    	pstmt.setInt(4, this.anno  );
	    	pstmt.setDate(5, this.uscita  );
	    	pstmt.setDouble(6, this.voto  );
	    	pstmt.setInt(7, this.durata  );
	    	pstmt.setInt(8, this.copieTotali  );
	    	pstmt.setInt(9, this.copieRimaste  );
	    	pstmt.setBoolean(10, this.visibile  );
	    	
	    	if ( this.id > 0 )
	    		pstmt.setInt(11, this.id  );
	    	
	    	
	    	rowAffected = pstmt.executeUpdate();
	    	if ( rowAffected > 0 ) {
	    		result = new Result(true, this, "Operazione di " + ( insert ? " insert" : "update" ) + " avvenuta con successo per film " + this.titolo +  " con ID " + this.id );
	    		
	    	} else {
	    		result = new Result(false, null, "Errore durante operazione di " + ( insert ? " insert" : "update" ) + " per film " + this.titolo +  " con ID " + this.id );
	    		if ( Test.DEBUG ) System.out.println("Errore durante operazione di " + ( insert ? " insert" : "update" ) + " per film " + this.titolo +  " con ID " + this.id);
	    	}
	    	
	    	
	    	
	    	
	    	//Aggiorno l'id del film	    	
	    	if ( insert ) {
	    		rs = pstmt.getGeneratedKeys(); 
	    		if ( rs != null && rs.next() ) {
	    			this.id = rs.getInt(1); 
	    			if ( Test.DEBUG ) System.out.println("Operazione di " + ( insert ? " insert" : "update" ) + " avvenuta con successo per film " + this.titolo +  " con ID " + this.id);
		    		result = new Result(true, this, "Operazione di insert avvenuta con successo per film " + this.titolo +  " con ID " + this.id );
	    		}
	    		rs.close();	
	    	}
	    	
	    	
	    	if ( Test.DEBUG && insert ) System.out.println("Salvo i registi/scrittori/attori");
	    	if ( result.result && insert ) { //procedo con il salvataggio dei registi/scrittori/attori
	    		Result parziale;
	    		
	    		parziale = loadCategoria(c);
	    		if ( Test.DEBUG && !parziale.result )
	    			System.out.println( parziale.toString() );
	    		
	    		for ( Regista p: this.registi ) {
	    			parziale = p.save(c, this.id);
	    		}
	    		for ( Scrittore p: this.scrittori) {
	    			parziale = p.save(c, this.id);
	    		}
	    		for ( Attore p: this.attori) {
	    			parziale = p.save(c, this.id);
	    		}
	    	}
	    	
	        pstmt.close();
	    	c.commit();
	    	
	    	c.setAutoCommit(true);
	    	
	    	
	    	
    	} catch(Exception e){
            System.out.println( "Errore generale: " +e.getMessage());
            result = new Result(false, null, "Errore generale: " +e.getMessage() + " per film con ID " + this.id );
            // rollback
            try{
            	System.out.println("Rollback, annullo modifiche al database");
                c.rollback();
            } catch(Exception eRollback){}
        
        } finally {
            try{
                if( rs != null )
                    rs.close();
                if( pstmt != null )
                    pstmt.close();
            } catch(Exception e){
                System.out.println(" Rilascio risorse non riuscito: "+e.getMessage());
                result = new Result(false, null, "Rilascio risorse non riuscito: "+e.getMessage() + " per film con ID " + this.id );
            }
        }

        return result;
    }

    public Result delete( Connection c ) {
        // cancellala dal db
    	String query = "";
    	PreparedStatement pstmt = null;
    	Result result = null;
    	int affectedRows = 0;
    	
    	try {
    		c.setAutoCommit(false);
    		query = "DELETE FROM " + tabName + " WHERE " + idField + " = ?";
    		pstmt = c.prepareStatement(query);
    		pstmt.setInt(1, this.id);
    		
    		affectedRows = pstmt.executeUpdate();
    		if ( affectedRows > 0 ) {
    			result = new Result ( true, null, "Record cancellato con film ID " + this.id );
	    	} else {
	    		result = new Result ( false, null, "Record NON cancellato con film ID " + this.id );
	    	}
    			
    		pstmt.close();
    		c.commit();

    		
    	} catch(Exception e){
    		System.out.println( "Errore generale: " +e.getMessage() + e.getLocalizedMessage() );
            result = new Result ( false, null, "Errore generale: " +e.getMessage() + "\nRecord non cancellato con film ID " + this.id );
            // rollback
            try{
            	System.out.println("Rollback, annullo modifiche al database");
                c.rollback();
            } catch(Exception eRollback){}
        
        } finally {
            try{
                if( pstmt != null )
                    pstmt.close();
            } catch(Exception e){
            	result = new Result ( false, null, "Rilascio risorse non riuscito: " +e.getMessage() + "\nRecord non cancellato con film ID " + this.id );
                System.out.println("Rilascio risorse non riuscito: "+e.getMessage());
            }
        }
        
        /* IMPOSTO TUTTI I RIFERIMENTI A NULL, SONO GIA' STATI ELIMINATI DAL DB TRAMITE CHIAVI ESTERNE */
        this.registi = null;
        this.attori = null;
        this.scrittori = null;
        this.categoria = null;
        
    	return result;
    }

    public String toString() {
    	
        String retS = "[" + this.id + " - " + this.visibile + "] " + this.titolo + "\n";
        retS += "--- Categoria: "+ this.categoria.toString() + "\n";
        retS += "--- Descrizione: "+ this.descrizione + "\n";
        retS += "--- Anno: "+ this.anno + "\n";
        retS += "--- Uscita: "+ this.uscita + "\n";
        retS += "--- Voto: "+ this.voto + "/10\n";
        retS += "--- Durata: "+ durataToString() + "\n";
        retS += "--- Copie Totali: "+ this.copieTotali + "\n";
        retS += "--- Copie Rimaste: "+ this.copieRimaste + "\n";
        
        retS += "--- Registi ("+ this.registi.size() +")\n";
        for ( Persona p: this.registi )
        	retS += "------ " + p.toString() + "\n";
        
        retS += "--- Scrittori ("+ this.scrittori.size() +")\n";
        for ( Persona p: this.scrittori )
        	retS += "------ " + p.toString() + "\n";
        
        retS += "--- Attori ("+ this.attori.size() +")\n";
        for ( Persona p: this.attori )
        	retS += "------ " + p.toString() + "\n";
        
        
        return retS;
    }



}
